﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.IO;
using System.Windows.Markup;

using Ionic.Zip;

using LibSnesDotNet.Core;

using OpenFileDialog = System.Windows.Forms.OpenFileDialog;

namespace LibSnesDotNet.UI
{
	public partial class UIWindow : OverlayWindow
	{
		#region Dependency Properties, Routed Events, and Commands

		static RoutedCommand _saveConfigCommand = new RoutedCommand("SaveConfig", typeof(UIWindow));
		public static RoutedCommand SaveConfigCommand { get { return _saveConfigCommand; } }
		static RoutedCommand _loadConfigCommand = new RoutedCommand("LoadConfig", typeof(UIWindow));
		public static RoutedCommand LoadConfigCommand { get { return _loadConfigCommand; } }

		static RoutedCommand _openGameCommand = new RoutedCommand("OpenGame", typeof(UIWindow));
		public static RoutedCommand OpenGameCommand { get { return _openGameCommand; } }

		static RoutedCommand _resetCommand = new RoutedCommand("Reset", typeof(UIWindow));
		public static RoutedCommand ResetCommand { get { return _resetCommand; } }
		static RoutedCommand _powerCycleCommand = new RoutedCommand("PowerCycle", typeof(UIWindow));
		public static RoutedCommand PowerCycleCommand { get { return _powerCycleCommand; } }

		static RoutedCommand _exitCommand = new RoutedCommand("Exit", typeof(UIWindow));
		public static RoutedCommand ExitCommand { get { return _exitCommand; } }

		static DependencyPropertyKey _configPropertyKey = DependencyProperty.RegisterReadOnly("Config",
		                                                                                      typeof(Configuration),
		                                                                                      typeof(UIWindow),
		                                                                                      new PropertyMetadata());
		public Configuration Config { get { return (Configuration)GetValue(_configPropertyKey.DependencyProperty); } }

		#endregion

		internal const string DefaultTheme = @"UI\DefaultTheme\DefaultTheme.xaml";

		OpenFileDialog _openGameDialog;

		string _cartridgePath;
		string _bsxPath;
		string _stAPath;
		string _stBPath;
		string _gbPath;

		public UIWindow(Configuration config)
		{
			SetValue(_configPropertyKey, config);

			CommandBindings.Add(new CommandBinding(_saveConfigCommand, SaveConfig_Execute));
			CommandBindings.Add(new CommandBinding(_loadConfigCommand, LoadConfig_Execute));
			CommandBindings.Add(new CommandBinding(_openGameCommand, OpenGame_Execute));
			CommandBindings.Add(new CommandBinding(_exitCommand, Exit_Execute));
			CommandBindings.Add(new CommandBinding(_resetCommand, Reset_Execute));
			CommandBindings.Add(new CommandBinding(_powerCycleCommand, PowerCycle_Execute));

			_openGameDialog = new OpenFileDialog() { Filter = "All Cartridge Files (*.sfc, *.smc, *.zip)|*.sfc;*.smc;*.zip|" +
			                                                  "SNES cartridge Files (*.sfc, *.smc)|*.sfc;*.smc|" +
			                                                  "Compressed Cartridge Files (*.zip)|*.zip"};

			_cartridgePath = "";
			_bsxPath = "";
			_stAPath = "";
			_stBPath = "";
			_gbPath = "";
		}

		public MainForm MainForm { get { return (MainForm)BaseForm; } }

		protected override void OnInitialized(EventArgs e)
		{
			base.OnInitialized(e);

			bool isThemeLoaded = false;
			do
			{
				string path = Config.UI.Theme.Source;
				try
				{
					if (!Path.IsPathRooted(path))
					{
						path = Path.Combine(Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), path);
					}

					ResourceDictionary theme = new ResourceDictionary()
					{
						Source = new Uri(path, UriKind.Absolute)
					};

					Resources.MergedDictionaries.Add(theme);
					isThemeLoaded = true;
				}
				catch
				{
					if (MessageBox.Show("Unable to load theme " + Config.UI.Theme.Source + "." + Environment.NewLine + "Use default instead?",
					                    "Error",
					                    MessageBoxButton.YesNo,
					                    MessageBoxImage.Error) == MessageBoxResult.Yes)
					{
						Config.UI.Theme.Source = DefaultTheme;
					}
					else
					{
						MainForm.BeginInvoke(new Action(() => { MainForm.Close(); }));
						return;
					}
				}
			} while (!isThemeLoaded);
		}

		protected override void OnMouseEnter(System.Windows.Input.MouseEventArgs e)
		{
			if (BaseForm.Focused) { Focus(); }

			base.OnMouseEnter(e);
		}

		protected override void OnMouseLeave(System.Windows.Input.MouseEventArgs e)
		{
			if (IsKeyboardFocusWithin) { BaseForm.Focus(); }

			base.OnMouseLeave(e);
		}

		protected override void OnClosed(EventArgs e)
		{
			SaveMemory();

			base.OnClosed(e);
		}

		void SaveMemory()
		{
			MainForm.CoreDriver.Stop();
			NormalCartridge cartridge = MainForm.CoreDriver.Snes.Cartridge as NormalCartridge;

			if (cartridge != null && cartridge.Sram != null)
			{
				string sramFileName = Path.ChangeExtension(_cartridgePath, ".srm");
				using (FileStream fs = new FileStream(sramFileName, FileMode.Create))
				{
					byte[] sram = ((NormalCartridge)cartridge).Sram;
					fs.Write(sram, 0, sram.Length);
				}
			}
		}

		private void SaveConfig_Execute(object sender, RoutedEventArgs e)
		{
			Config.Save();
		}

		private void LoadConfig_Execute(object sender, RoutedEventArgs e)
		{
			Config.Load();
		}

		private void OpenGame_Execute(object sender, RoutedEventArgs e)
		{
			if (_openGameDialog.ShowDialog(BaseForm) == System.Windows.Forms.DialogResult.OK)
			{
				if (!File.Exists(_openGameDialog.FileName))
				{
					MessageBox.Show("File does not exist.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
					return;
				}

				byte[] rom = null;
				if (Path.GetExtension(_openGameDialog.FileName).ToLower() == ".zip")
				{
					ZipFile zip = ZipFile.Read(_openGameDialog.FileName);
					foreach (ZipEntry entry in zip)
					{
						string extenstion = Path.GetExtension(entry.FileName).ToLower();
						if (extenstion == ".sfc" || extenstion == ".smc")
						{
							rom = new byte[entry.UncompressedSize];
							var romStream = new MemoryStream(rom);
							entry.Extract(romStream);
							break;
						}
					}
				}
				else
				{
					using (FileStream fs = new FileStream(_openGameDialog.FileName, FileMode.Open))
					{
						rom = new byte[fs.Length];
						fs.Read(rom, 0, (int)fs.Length);
					}
				}


				string sramFileName = Path.ChangeExtension(_openGameDialog.FileName, ".srm");
				byte[] sram = null;
				if (File.Exists(sramFileName))
				{
					using (FileStream fs = new FileStream(sramFileName, FileMode.Open))
					{
						sram = new byte[fs.Length];
						fs.Read(sram, 0, (int)fs.Length);
					}
				}

				MainForm.CoreDriver.Stop();
				SaveMemory();
				MainForm.CoreDriver.Snes.LoadCartridge(new NormalCartridge() { RomData = rom, Sram = sram });
				_cartridgePath = _openGameDialog.FileName;
				MainForm.CoreDriver.Start();
			}

			Focus();
		}

		private void Reset_Execute(object sender, RoutedEventArgs e)
		{
			bool wasRunning = MainForm.CoreDriver.IsRunning;
			MainForm.CoreDriver.Stop();
			MainForm.CoreDriver.Snes.Reset();
			if (wasRunning) { MainForm.CoreDriver.Start(); }
		}

		private void PowerCycle_Execute(object sender, RoutedEventArgs e)
		{
			Console.WriteLine("power");
			bool wasRunning = MainForm.CoreDriver.IsRunning;
			MainForm.CoreDriver.Stop();
			MainForm.CoreDriver.Snes.PowerCycle();
			if (wasRunning) { MainForm.CoreDriver.Start(); }
		}

		private void Exit_Execute(object sender, RoutedEventArgs e)
		{
			MainForm.Close();
		}


	}
}
